package org.apache.commons.beanutils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Map;

import com.google.common.base.Throwables;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * 基于反射实现对类的字段{@link Field}读写
 * @author guyadong
 *
 */
public class FieldPropertyDescriptor extends PropertyDescriptor implements MorePropertyDescriptor {

	private static final Map<String, Field> fields= new Hashtable<>();
	private final Method readMethod;
	private final Method writeMethod;
	private final Class<?> propertyType;
	FieldPropertyDescriptor(Field field)
			throws IntrospectionException {
		super(checkNotNull(field,"field is null").getName(), null, null);
		this.propertyType = field.getType();
		fields.put(field.getName(), field);
		try {
			readMethod = FieldPropertyDescriptor.class.getMethod("readMethod", Object.class,String.class);
			writeMethod = FieldPropertyDescriptor.class.getMethod("writeMethod", Object.class,String.class,Object.class);
		} catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}
	private static Field getAccessibleField(String name){
		Field field = checkNotNull(fields.get(name),"INVALID field name %s",name);
		if(!field.isAccessible()){
			field.setAccessible(true);
		}
		return field;
	}
	/**
	 * 字段读取方法实现
	 * @param bean 读取目标对象
	 * @param name 字段名
	 * @return 字段值
	 */
	public static Object readMethod(Object bean,String name){
		if(null != bean){
			try {
				return getAccessibleField(name).get(bean);
			} catch (Exception e) {
				Throwables.throwIfUnchecked(e);
				throw new RuntimeException(e);
			}
		}
		return null;		
	}
	/**
	 * 字段写入方法实现
	 * @param bean 写入目标对象
	 * @param name 字段名
	 * @param value 要写入的值
	 */
	public static void writeMethod(Object bean,String name,Object value){
		if(null != bean){
			try{
				getAccessibleField(name).set(bean, value);
			} catch (Exception e) {
				Throwables.throwIfUnchecked(e);
				throw new RuntimeException(e);
			}
		}
	}

	@Override
	public Method getReadMethod() {
		return readMethod;
	}

	@Override
	public Method getWriteMethod() {
		return writeMethod;
	}

	@Override
	public Class<?> getPropertyType() {
		return propertyType;
	}
	
}
